﻿using DotNetCore.CAP;
using DotNetCore.CAP.Messages;
using DotNetCore.CAP.Transport;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace CapHttp.Core;

public class HttpTransport : ITransport
{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly CapHttpOptions  _options;
    private readonly ILogger<HttpTransport> _logger;

    public HttpTransport(IHttpClientFactory httpClientFactory, IOptions<CapHttpOptions> optionsAccessor, ILogger<HttpTransport> logger)
    {
        _httpClientFactory = httpClientFactory;
        _logger = logger;
        _options = optionsAccessor.Value;
    }
    
    public async Task<OperateResult> SendAsync(TransportMessage message)
    {
        var httpClient = _httpClientFactory.CreateClient();
        if (message.Headers.TryGetValue(CapHttpConstants.API_NAME_HEADER, out var apiName))
        {
            if (_options.Apis.TryGetValue(apiName!, out var apiAddress))
            {
                var content = new ReadOnlyMemoryContent(message.Body);
                try
                {
                    foreach (var messageHeader in message.Headers)
                    {
                        if (messageHeader.Key == Headers.Exception) continue;
                        content.Headers.Add(messageHeader.Key, messageHeader.Value);
                    }
                    content.Headers.Add("Content-Type", "application/json");
                }
                catch (FormatException ex)
                {
                    _logger.LogError(ex, ex.Message);
                    return OperateResult.Failed(ex);
                }

                try
                {
                    var responseMessage = await httpClient.PostAsync(apiAddress, content);
                    if (responseMessage.IsSuccessStatusCode)
                        return OperateResult.Success;
                
                    var responseText = await responseMessage.Content.ReadAsStringAsync();
                    return OperateResult.Failed(new Exception($"{responseMessage.StatusCode}: {responseMessage.ReasonPhrase} {responseText}"));
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, ex.Message);
                    return OperateResult.Failed(ex);
                }
            }
        }

        return OperateResult.Failed(new Exception("Api Address not found"));
    }

    public BrokerAddress BrokerAddress => new BrokerAddress("Http");
}